package geecache

import (
	"fmt"
	"geecache/singleflight"
	"log"
	"sync"
)



type Getter interface {
	// 根据 key 拿到对应的缓存值
	Get(key string) ([]byte, error)
}

// 函数类型实现某个接口，称之为接口型函数。
// 回调函数类型
type GetterFunc func(key string) ([]byte, error)
// 此函数类型实现了 Getter 接口
func (f GetterFunc) Get(key string) ([]byte, error) {
	// 调用自己
	return f(key)
}
// 对应某种类型缓存
type Group struct {
	// 某一类缓存的名字
	name string
	// 缓存未命中时需要回调的函数
	getter Getter
	// 对应并发缓存实体
	mainCache cache
	peers PeerPicker
	loader *singleflight.Group
}

var (
	mu sync.RWMutex
	// 全局变量
	groups = make(map[string]*Group)
)
// 注册节点
func (g *Group) RegisterPeers(peers PeerPicker) {
	if g.peers != nil {
		panic("RegisterPeerPicer called more than once")
	}
	g.peers = peers

}

func (g *Group) load(key string) (value ByteView, err error) {
	// 保证 在并发情况下，针对相同的 key, load动作只会被调用一次
	viewi, err := g.loader.Do(key, func() (interface{}, error) {
		if g.peers != nil {
			if peer, ok := g.peers.PickPeer(key); ok {
				if value, err := g.getFromPeer(peer, key); err == nil {
					return value, nil
				}
				log.Println("[GeeCache] Failed to get from peer", err)
			}
		}
		return g.getLocally(key)
	})

	if err == nil {
		return viewi.(ByteView), nil
	}
	return


}

func (g *Group) getFromPeer(peer PeerGetter, key string) (ByteView, error) {

	bytes, err := peer.Get(g.name, key)
	if err != nil {
		return ByteView{}, err
	}
	return ByteView{
		b: bytes,
	}, nil
}


// 创建命名空间
func NewGroup(name string, cacheBytes int64, getter Getter) *Group {
	if getter == nil {
		panic("nil Getter")

	}
	// map是并发不安全的，对其进行操作需要使用锁
	mu.Lock()
	defer mu.Unlock()
	g := &Group{
		name: name,
		getter: getter,
		mainCache: cache{cacheBytes: cacheBytes},
		loader: &singleflight.Group{},

	}
	groups[name] = g
	return g
}


func GetGroup(name string) *Group {
	// 只读锁
	mu.RLock()
	g := groups[name]
	mu.RUnlock()
	return g
}
// 从命名空间拿取缓存
func (g *Group) Get(key string) (ByteView, error) {
	if key == "" {
		return ByteView{}, fmt.Errorf("key is required")
	}
	// 从缓存中查找

	if v, ok := g.mainCache.get(key); ok {
		log.Println("[Geecache] hit")
		return v, nil
	}
	// 如果缓存不存在，则需要获取源数据
	return g.load(key)
}


func (g *Group) getLocally(key string) (ByteView, error) {
	// 使用回调函数从源获得key对应的原始数据
	// 获取逻辑用户自己写，但是必须要符合我的参数规范，即我传一个 key string, 你返回 []byte类型
	bytes, err := g.getter.Get(key)
	if err != nil {
		return ByteView{}, err
	}
	value := ByteView{
		// 拷贝一份源数据
		b: cloneBytes(bytes),
	}
	// 添加到缓存中
	g.populateCache(key, value)
	return value, nil
}
func (g *Group) populateCache(key string, value ByteView) {
	g.mainCache.add(key, value)
}

